package com.demo.crud.service;

import com.demo.crud.dao.UserDao2;
import com.demo.crud.entities.User;
import org.springframework.aop.framework.AopContext;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Description:
 * @Author: kt
 * @CreateTime: 2021/2/26
 */
@Service
public class TestService {

    @Autowired
    private UserDao2 userDao2;

    private volatile boolean rollback;

    @Autowired
    private PlatformTransactionManager transactionManager;

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void test(int i, List<TransactionStatus> transactionStatusList, CountDownLatch countDownLatch, CountDownLatch m) {
        /*DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
        TransactionStatus status = transactionManager.getTransaction(def);
        transactionStatusList.add(status);*/

        TransactionStatus status = TransactionAspectSupport.currentTransactionStatus();
        transactionStatusList.add(status);
        User user = new User();
        user.setLastIp(UUID.randomUUID().toString());
        user.setUserName("Test111");
        user.setPassword("Passsword1111");
        try {
            userDao2.insert(user);
            if (i == 2) {
                System.out.println("test1111111111111111");
                int j = i / 0;
            }
        } catch (Exception e) {
            e.printStackTrace();
            status.setRollbackOnly();
        } finally {
            countDownLatch.countDown();
            try {
                m.await();
                System.out.println("111111111");
            } catch (InterruptedException e) {
            }
            if (this.rollback) {
                transactionManager.rollback(status);
                System.out.println("222222");
            } else {
                transactionManager.commit(status);
                System.out.println("33333");
            }
        }
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void test2() throws InterruptedException {
        TestService testService = (TestService)AopContext.currentProxy();
        TransactionStatus status = TransactionAspectSupport.currentTransactionStatus();
        CountDownLatch m = new CountDownLatch(1);
        List<TransactionStatus> transactionalList = Collections.synchronizedList(new ArrayList<>());
        CountDownLatch countDownLatch = new CountDownLatch(4);
        AtomicInteger atomicInteger = new AtomicInteger(1);
        for (int i = 0; i < 4; i++) {
            new Thread(() -> {
                testService.test(atomicInteger.getAndIncrement(), transactionalList, countDownLatch, m);
            }).start();
        }
        countDownLatch.await();
        boolean anyMatch = transactionalList.stream().anyMatch(ts -> ts.isRollbackOnly());
        this.rollback = anyMatch;
        m.countDown();
    }
}
